#include "stdafx.h"
#include "CppUnitTest.h"

#include "System/Base/Buffer.h"
#include "System/Base/Exceptions.h"
#include "System/Utility/Testing.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace Native::System;
using namespace Native { namespace System::Utility;

namespace TestNativeSystem
{
    TEST_CLASS(Buffer_Tester)
    {
    public:
        mstring _first_text;
        mstring _second_text;
        CBuffer _base;

    private:
        void CheckNewBufferSize(const CBuffer& buffer, size_t expected_capacity)
        {
            Assert::AreEqual(buffer.Capacity(), expected_capacity);
            Assert::AreEqual(buffer.Usage(), 0u);
        }

    public:
        Buffer_Tester() :
            _first_text("First"),
            _second_text("Second")
        {
            _base.Import((pointer_t)_first_text.c_str(), _first_text.length());
        }

        TEST_METHOD(Buffer_EqualTo)
        {
            CBuffer contrast(12);

            contrast.Import((pointer_t)_second_text.c_str(), _second_text.length());

            UEquivalentTester::CheckByEqualTo<CBuffer>(
                dynamic_cast<IEqualTo<CBuffer>*>(&_base),
                contrast,
                false);
        }

        TEST_METHOD(Buffer_Construct)
        {
            UConstructorTester::CheckByEqualTo<CBuffer>(_base);
        }

        TEST_METHOD(Buffer_ConstructDefault)
        {
            CBuffer buffer;

            Assert::AreEqual(buffer.Capacity(), CBuffer::DEFAULT_UNIT_CAPACITY);
            Assert::AreEqual(buffer.Usage(), 0u);
        }
        
        TEST_METHOD(Buffer_ConstructObjectAllocateSize)
        {
            CheckNewBufferSize(CBuffer(12), 32u);
            CheckNewBufferSize(CBuffer(32), 32u);
            CheckNewBufferSize(CBuffer(64), 64u);
            CheckNewBufferSize(CBuffer(12, 1024), 1024u);
            CheckNewBufferSize(CBuffer(1024, 1024), 1024u);
            CheckNewBufferSize(CBuffer(1028, 1024), 2048u);
            CheckNewBufferSize(CBuffer(2047, 1024), 2048u);

            function<void (void)> throw_exception = [] {
                CBuffer buffer(0, 1024);
            };

            Assert::ExpectException<CException>(throw_exception);
        }
        
        TEST_METHOD(Buffer_ImportSmallerData)
        {
            CBuffer buffer;
            wchar_t export[30] = {0};

            buffer.Import((pointer_t)_first_text.c_str(), _first_text.length());
            buffer.Export((pointer_t)export, 30);

            Assert::AreEqual(buffer.Capacity(), CBuffer::DEFAULT_UNIT_CAPACITY);
            Assert::AreEqual(buffer.Usage(), _first_text.length());
        }

        TEST_METHOD(Buffer_ImportDataAutoExtendSize)
        {
            CBuffer buffer(1, 1);

            buffer.Import((pointer_t)_first_text.c_str(), _first_text.length());

            Assert::AreEqual(buffer.Capacity(), 5u);
            Assert::AreEqual(buffer.Usage(), _first_text.length());
        }

        TEST_METHOD(Buffer_ImportDataForbidExtending)
        {
            function<void(void)> throw_exception = [&] {
                CBuffer buffer(1, 1, BUFFER_IMPORT_RULE_THROW);

                buffer.Import((pointer_t)_first_text.c_str(), _first_text.length());
            };

            Assert::ExpectException<CException>(throw_exception);
        }

        TEST_METHOD(Buffer_ImportDataDiscardRedundance)
        {
            CBuffer buffer(2, 1, BUFFER_IMPORT_RULE_DISCARD);

            buffer.Import((pointer_t)_first_text.c_str(), _first_text.length());

            Assert::AreEqual(buffer.Capacity(), 2u);
            Assert::AreEqual(buffer.Usage(), 2u);
        }

        TEST_METHOD(Buffer_ClearBuffer)
        {
            CBuffer buffer;

            buffer.Import((pointer_t)_first_text.c_str(), _first_text.length());
            buffer.Clear();

            CheckNewBufferSize(buffer, CBuffer::DEFAULT_UNIT_CAPACITY);
        }

        TEST_METHOD(Buffer_AppendSmallerSize)
        {
            CBuffer buffer;

            Assert::AreEqual(buffer.Import((pointer_t)_first_text.c_str(), _first_text.length()), _first_text.length());

            buffer.Append((pointer_t)_second_text.c_str(), _second_text.length());

            Assert::AreEqual(buffer.Usage(), _first_text.length()+_second_text.length());
        }
    };
}